package com.gsm.aggreagte;

import com.gsm.bean.WaterSensor;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

/**
 * TODO
 *
 * @author gsm
 * @version 1.0
 */
public class KeybyDemo {

    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(2);


        DataStreamSource<WaterSensor> sensorDS = env.fromElements(
                new WaterSensor("s1", 1L, 1),
                new WaterSensor("s1", 11L, 11),
                new WaterSensor("s2", 2L, 2),
                new WaterSensor("s3", 3L, 3)
        );

        // 按照 id 分组
        /**
         * TODO keyby： 按照id分组
         * 要点：
         *  1、返回的是一个 KeyedStream，键控流 ,之前讲的map等转换算子返回的是SingleOutputStreamOperator
         *  2、keyby不是 转换算子， 只是对数据进行重分区, 不能设置并行度
         *  3、分组 与 分区 的关系：
         *    1） keyby是对数据分组，保证 相同key的数据 在同一个分区（子任务）
         *    2） 分区： 一个子任务可以理解为一个分区，一个分区（子任务）中可以存在多个分组（key）
         */
        KeyedStream<WaterSensor, String> sensorKS = sensorDS
                .keyBy(new KeySelector<WaterSensor, String>() {
                    @Override
                    public String getKey(WaterSensor value) throws Exception {
                        return value.getId();
                    }
                });

        sensorKS.print();


        env.execute();
    }


}

/*
Apache Flink 是一个用于分布式数据流处理的开源框架，它支持事件驱动的处理模型以及批处理模式。在 Flink 中，分区（Partitioning）和分组（Grouping）是两个不同的概念，它们都用于控制数据如何在并行任务之间分布，但是应用的场景和作用有所不同。

### 分区（Partitioning）

分区是指如何将数据集中的记录分配到多个计算节点上。在 Flink 中，分区通常发生在 shuffle 或者 rebalance 操作中，当数据需要从一个操作符发送到下一个操作符时，需要确定每个记录应该发往哪个下游任务实例。常见的分区策略包括：

- **散列分区（Hash Partitioning）**：根据记录的一个或多个字段的哈希值来决定其去向。
- **范围分区（Range Partitioning）**：基于键的值域来分配记录。
- **轮询负载（Round-robin Load）**：无特定规则地将记录均匀地分布到所有可用的下游任务中。
- **全局分区（Global Partitioning）**：所有的记录都被发送到同一个任务实例。
- **复制（Replication）**：所有记录被复制到所有下游任务实例。

### 分组（Grouping）

分组则是指在执行某些操作之前，先对数据进行分类整理的过程。例如，在进行聚合操作（如 sum, average, min/max 等）之前，需要确保所有具有相同键的数据能够聚集在一起。Flink 支持几种不同的分组方式：

- **全分组（All Grouping）**：将所有数据合并到一组。
- **字段分组（Field Grouping）**：基于数据中的一个或多个字段进行分组。
- **部分分组（Partial Grouping）**：仅基于部分字段进行分组。
- **非分组（No Grouping）**：不进行任何分组，保持数据原样。

在实际应用中，分区更多是在数据传输过程中决定数据流向的方式，而分组则是在本地处理逻辑中决定如何对数据进行组织的方法。两者都是为了实现更高效的数据处理流程。

 */